#include "hzpch.h"
#include "OpenGLTexture.h"
#include "stb_image.h"

#include <glad/glad.h>

namespace Hazal
{
	COpenGLTexture2D::COpenGLTexture2D(uint32_t unWidth, uint32_t unHeight)
		:m_unWidth(unWidth), m_unHeight(unHeight)
	{
		glCreateTextures(GL_TEXTURE_2D, 1, &m_unRendererID);
		glTextureStorage2D(m_unRendererID, 1, GL_RGBA8, m_unWidth, m_unHeight);

		glTextureParameteri(m_unRendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTextureParameteri(m_unRendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		glTextureParameteri(m_unRendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTextureParameteri(m_unRendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);

	}

	COpenGLTexture2D::COpenGLTexture2D(const std::string& strFilePath)
		:m_unWidth(0), m_unHeight(0), m_unRendererID(0), m_strFilePath(strFilePath)
	{
		int nWidth, nHeight, nChannel;
		stbi_set_flip_vertically_on_load(1);
		stbi_uc* pData = stbi_load(strFilePath.c_str(), &nWidth, &nHeight, &nChannel, 0);

		HZ_CORE_ASSERT(pData, "Faile to Load image!");

		GLenum eInterChannel = 0, eDataChannel = 0;
		unsigned short usGLChannel = 0;
		if (3 == nChannel)
		{
			eInterChannel = GL_RGB8;
			eDataChannel = GL_RGB;
		}
		else if (4 == nChannel)
		{
			eInterChannel = GL_RGBA8;
			eDataChannel = GL_RGBA;
		}
		else
		{
			LOG_CORE_INFO("Unknow image channel({0})!", nChannel);
		}

		m_unWidth = nWidth;
		m_unHeight = nHeight;

		glCreateTextures(GL_TEXTURE_2D, 1, &m_unRendererID);
		glTextureStorage2D(m_unRendererID, 1, eInterChannel, m_unWidth, m_unHeight);

		glTextureParameteri(m_unRendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTextureParameteri(m_unRendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		glTextureParameteri(m_unRendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTextureParameteri(m_unRendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glTextureSubImage2D(m_unRendererID, 0, 0, 0, m_unWidth, m_unHeight, eDataChannel, GL_UNSIGNED_BYTE, pData);

		stbi_image_free(pData);
	}

	COpenGLTexture2D::~COpenGLTexture2D()
	{
		glDeleteTextures(1, &m_unRendererID);
	}

	void COpenGLTexture2D::SetData(void* pData, uint32_t unSize)
	{
		HZ_CORE_ASSERT(unSize == m_unWidth * m_unHeight * 4, "Data must be entire texture!")
		glTextureSubImage2D(m_unRendererID, 0, 0, 0, m_unWidth, m_unHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData);
	}

	void COpenGLTexture2D::Bind(uint32_t unSlot) const
	{
		glBindTextureUnit(unSlot, m_unRendererID);
	}

	void COpenGLTexture2D::Unbind() const
	{
		glBindTexture(GL_TEXTURE_2D, 0);
	}
	bool COpenGLTexture2D::operator==(const CTexture& rOther) const
	{
		return m_unRendererID == ((COpenGLTexture2D&)rOther).m_unRendererID;
	}
}